#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import os

try:
    from .nodes import *
    from .lexer_common import GVCLexerBase
except:
    from nodes import *
    from lexer_common import GVCLexerBase

import pycparser
from ply import yacc
from pycparser.c_ast import _repr
from pycparser.plyparser import (PLYParser, Coord, ParseError,
                                 template)

from ctools.logext import *

logname = os.path.realpath(__file__)
_rlog, _plog, _mlog, _tlog = get_loggers(__file__, __name__, propagate=False)

def prepare_yacctab(parser):
    if hasattr(parser, 'start_parse'):
        parser.start_parse('dummy')
    treenode = parser.parse_text('')

@template
class GVCParserBase(PLYParser):
    def __init__(self,
                lex_optimize=True,
                lexer=GVCLexerBase,
                lextab='ctools.ly_parser.lextab',
                yacc_optimize=True,
                yacctab='ctools.ly_parser.gvc_yacctab',
                yacc_debug=False,
                debugfile='gvc_yacc.out',
                taboutputdir='',
                **kwargs) -> None:
        self.clex = lexer()
        self.tokens = self.clex.tokens
        self.cparser = yacc.yacc(module=self,
                            debug=yacc_debug,
                            debugfile=debugfile,
                            optimize=yacc_optimize,
                            tabmodule=yacctab,
                            outputdir=taboutputdir,
                            **kwargs
                        )
        # self.clex.reset_lineno()

    def set_coord_filename(self, filename):
        self.clex.filename = filename

    def parse_text(self, text, filename='', debug=False):
        """ Parses C code
            text:
                A string containing the C source code
            filename:
                Name of the file being parsed (for meaningful
                error messages)
            debug:
                Debug flag to YACC
        """

        if filename:
            self.clex.filename = filename
        return self.cparser.parse(
                input=text,
                lexer=self.clex,
                debug=debug)

    def parse(self, filename, cpp_path='cpp', cpp_args=['-E', '-O0'], debug=False):
        text = pycparser.preprocess_file(filename, cpp_path=cpp_path, cpp_args=cpp_args)
        return self.parse_text(text, filename, debug)

    def _coord(self, lineno, column=None):
        return Coord(
                file=self.clex.filename,
                line=lineno,
                column=column)

    def _token_coord(self, p, token_idx):
        """ Returns the coordinates for the YaccProduction object 'p' indexed
            with 'token_idx'. The coordinate includes the 'lineno' and
            'column'. Both follow the lex semantic, starting from 1.
        """
        last_cr = p.lexer.lexer.lexdata.rfind('\n', 0, p.lexpos(token_idx))
        if last_cr < 0:
            last_cr = -1
        column = (p.lexpos(token_idx) - (last_cr))
        ret = self._coord(p.lineno(token_idx), column)
        _mlog.debug(ret)
        return ret

    def _parse_error(self, msg, coord):
        raise ParseError("%s: %s" % (coord, msg))
